iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0

https://ithelp.ithome.com.tw/upload/images/20220912/20151958IFjRs0xIZ4.png Medium 好讀版

此系列文章是以我的業餘專案: Kimoji 作為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!

https://ithelp.ithome.com.tw/upload/images/20220907/20151958vXuPLv4aki.png 立馬下載 https://ithelp.ithome.com.tw/upload/images/20220907/20151958LtM1NGErzK.png 限免兌換碼

在 Compose 當中,我們是不用隱藏 UI 元件的。只要我們不把這些元件加到 composition 裡就好,然後這些元件就不會加入 Compose 產生的 UI 樹狀結構了。只要使用簡單的 Kotlin 條件式邏輯就能達到這個效果。舉例來說,如果想顯示 onboarding 畫面,或日記本,我們可以這樣做:

@Composable
fun KimojiApp() {
    if (shouldShowOnboarding) { // Where does this come from?
        OnboardingScreen()
    } else {
        Journal()
    }
}

但是,我們無法存取 shouldShowOnboarding。顯然我們需要和 KimojiApp composable 分享我們在 OnboardingScreen 建立的狀態。

我們不用想辦法把值分享給 parent,只要「hoist」就好,直接把值移動到需要存取的 common ancestor 裡面。

像是這樣:

@Composable
fun KimojiApp() {

    var shouldShowOnboarding by remember { mutableStateOf(true) }

    if (shouldShowOnboarding) {
        OnboardingScreen(/* TODO */)
    } else {
        Journal()
    }
}

我們還需要和 onboarding 畫面分享 shouldShowOnboarding,但是不必直接進行傳遞。我們可以不讓 OnboardingScreen 變更狀態,而是讓它通知我們使用者已經按下「Hi, Kimoji!」 按鈕,這樣的處理方式比較好。

如何向上傳遞事件呢?答案是向下傳遞 callbacks。Callbacks 是傳遞給其他函式當做參數的函式,在觸發事件時,就會執行這個函式。

我們來試著為 onboarding 畫面新增函式參數,定義為 onHiClicked: () -> Unit,以便變更 KimojiApp 裡的狀態。

解法:

@Composable
fun KimojiApp() {

    var shouldShowOnboarding by remember { mutableStateOf(true) }

    if (shouldShowOnboarding) {
        OnboardingScreen(onHiClicked = { shouldShowOnboarding = false })
    } else {
        Journal()
    }
}

@Composable
fun OnboardingScreen(onHiClicked: () -> Unit) {

    Surface {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Image(
                painter = painterResource(R.drawable.joy),
                contentDescription = null,
                modifier = Modifier
                    .padding(vertical = 24.dp)
                    .size(40.dp)
                    .clip(CircleShape)
            )
            Text("Welcome to the Kimoji!")
            Button(
                modifier = Modifier.padding(vertical = 24.dp),
                onClick = onHiClicked
            ) {
                Text("Hi, Kimoji!")
            }
        }
    }
}

藉由傳遞函式 (而不是 state) 給 OnboardingScreen,這個 composable 可以更容易被複用,也能保護 state 不會因為其他 composable 而變動。大致上來說,這個方法可以讓一切都簡潔許多。我們可以來看看現在如何修改 onboarding 的 preview 畫面來呼叫 OnboardingScreen

@Preview(showBackground = true, widthDp = 320, heightDp = 320)
@Composable
fun OnboardingPreview() {
    KimojiTheme {
        OnboardingScreen(onHiClicked = {}) // Do nothing on click.
    }
}

onHiClicked 指派給空白的 lambda 代表「什麼都不做」,這十分適合給預覽畫面使用。

此系列文章是以我的業餘專案:Kimoji 為範例。

Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!

https://ithelp.ithome.com.tw/upload/images/20220907/20151958vXuPLv4aki.png 立馬下載 https://ithelp.ithome.com.tw/upload/images/20220907/20151958LtM1NGErzK.png 限免兌換碼

Reference: https://developer.android.com/codelabs/jetpack-compose-basics


上一篇
State hoisting
下一篇
Compose 狀態留存
系列文
Kimoji:以 Jetpack Compose 實作一款「心情日記」應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言